package com.zxing.practice.service.system;

import com.mybatisflex.core.query.QueryWrapper;
import com.zxing.practice.config.SysConstant;
import com.zxing.practice.config.vo.LoginInfo;
import com.zxing.practice.config.vo.LoginUser;
import com.zxing.practice.mapper.system.SysRolePermissionMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import static com.mybatisflex.core.query.QueryMethods.distinct;
import static com.zxing.practice.entity.system.table.RolePermissionEntityTableDef.ROLE_PERMISSION_ENTITY;

@Service("ss")
public class PermissionService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private SysRolePermissionMapper rolePermissionMapper;

    private LoginUser getLoginUser(){
        return (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    }

    private Set<String> roles(){
        LoginUser loginUser = getLoginUser();
        Collection<? extends GrantedAuthority> authorities = loginUser.getAuthorities();
        return authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet());
    }

    private Set<String> permissions(){
        LoginUser loginUser = getLoginUser();
        String username = loginUser.getUsername();
        LoginInfo loginInfo = (LoginInfo)redisTemplate.opsForValue().get(SysConstant.TOKEN_KEY_HEADER + username);
        return loginInfo == null ? new HashSet<>(0) : loginInfo.getPermissions();
    }

    public List<String> permissionsUseCache(LoginUser loginUser) {
        Set<String> roleIdSet = permissions();
        QueryWrapper queryWrapper = QueryWrapper.create()
                .select(distinct(ROLE_PERMISSION_ENTITY.PERMISSION))
                .from(ROLE_PERMISSION_ENTITY)
                .where(ROLE_PERMISSION_ENTITY.ROLE_ID.in(roleIdSet));
        return rolePermissionMapper.selectListByQueryAs(queryWrapper, String.class);
    }

    public boolean hasPermission(String permission){
        LoginUser loginUser = getLoginUser();
        List<String> permissions = permissionsUseCache(loginUser);
        return permissions.contains(permission);
    }

    public boolean hasAnyPermissions(String... permissions){
        List<String> list = Arrays.asList(permissions);
        LoginUser loginUser = getLoginUser();
        List<String> userPermissions = permissionsUseCache(loginUser);;
        return userPermissions.stream().anyMatch(list::contains);
    }

    public boolean hasRole(String role){
        Set<String> roleIdSet = roles();
        return roleIdSet.contains(role);
    }

    public boolean hasAnyRoles(String... roles){
        List<String> list = Arrays.asList(roles);
        Set<String> roleIdSet = roles();
        return roleIdSet.stream().anyMatch(list::contains);
    }
}
